#include "sudokuwidget.h"
#include <QDebug>
#include <QPainter>
#include "sudokucellsignals.h"

namespace sudoku_ui
{
    SudokuWidget::SudokuWidget(QWidget *parent)
        : QWidget{parent}
    {
        m_lineColor = QColor::fromRgb(112, 128, 144);
        for (auto i = 1; i <= 9; i++)
        {
            m_numcells.insert(std::make_pair(i, std::vector<SudokuCell*>()));
            m_numcells[i - 1].resize(9);
            m_ninecells.insert(std::make_pair(i, std::vector<SudokuCell*>(9, nullptr)));
        }

        m_board = std::vector<std::vector<SudokuCell*>>(9, std::vector<SudokuCell*>(9, nullptr));
        // 初始化存储单元格的存储空间
        for (auto i = 1; i <= 9; i++)
        {
            for (auto j = 1; j <= 9; j++)
            {
                auto cell = new SudokuCell(i, j, this);
                m_board[i - 1][j - 1] = cell;
                auto m = (i - 1) / 3 * 3 + (j - 1) / 3 + 1;     // 计算九宫格编号
                auto n = (i - 1) % 3 * 3 + (j - 1) % 3;     // 计算单元格在九宫格中的编号
                m_ninecells[m][n] = cell;
            }
        }

        connect(SudokuCellSignals::globalInstance(),
                &SudokuCellSignals::selectedCell,
                this,
                &SudokuWidget::onSelectedCell);

        connect(SudokuCellSignals::globalInstance(),
                &SudokuCellSignals::appendCell,
                this,
                &SudokuWidget::onAppendCell);

        connect(SudokuCellSignals::globalInstance(),
                &SudokuCellSignals::removeCell,
                this,
                &SudokuWidget::onRemoveCell);

        connect(SudokuCellSignals::globalInstance(),
                &SudokuCellSignals::checkNum,
                this,
                &SudokuWidget::onCheckGame);
    }

    SudokuWidget::~SudokuWidget()
    {
        for (auto& cells : m_ninecells)
        {
            cells.second.clear();
        }

        for (auto& cells : m_numcells)
        {
            cells.second.clear();
        }

        for (auto& cells : m_board)
        {
            for (auto& cell : cells)
            {
                cell->deleteLater();
            }
            cells.clear();
        }
        m_board.clear();
    }

    void SudokuWidget::setLineColor(const QColor &color)
    {
        if (m_lineColor == color)
            return;
        m_lineColor = color;
        update();
    }

    const QColor &SudokuWidget::lineColor() const
    {
        return m_lineColor;
    }

    void SudokuWidget::setNumbers(const std::vector<std::vector<int> > &numbers)
    {
        for (auto i = 0; i < 9; i++)
        {
            for (auto j = 0; j < 9; j++)
            {
                if (numbers[i][j] > 0)
                {
                    m_board[i][j]->setValue(numbers[i][j]);
                    m_board[i][j]->setFixed(true);
                }
            }
        }

    }

    std::vector<std::vector<int> > SudokuWidget::getNumbers() const
    {
        auto result = std::vector<std::vector<int>>(9, std::vector<int>(9, 0));

        for (auto i = 0; i < 9; i++)
        {
            for (auto j = 0; j < 9; j++)
            {
                result[i][j] = m_board[i][j]->value();
            }
        }

        return result;
    }

    void SudokuWidget::clear()
    {
        // 清除所有单元格的数值
        for (auto i = 0; i < 9; i++)
        {
            for (auto j = 0; j < 9; j++)
            {
                m_board[i][j]->setFixed();
                m_board[i][j]->setValue();                
                m_board[i][j]->clearHintValue();
            }
        }

        //
        if (m_selectedCell != nullptr)
        {
            m_selectedCell->unSelect();
            m_selectedCell = nullptr;
        }

        for (auto& cells : m_numcells)
        {
            cells.second.clear();
        }
    }

    void SudokuWidget::setSudokuValue(int value)
    {
        if (m_selectedCell == nullptr)
            return;

        m_selectedCell->setValue(value);
    }

    void SudokuWidget::setSudokuHintValue(int value)
    {
        if (m_selectedCell == nullptr)
            return;

        m_selectedCell->updateValue(value);
    }

    bool SudokuWidget::isValid(int row, int col, int value)
    {
        // 检查行
        for (auto i = 0; i < 9; i++)
        {
            if (i == col) continue;
            if (m_board[row][i]->value() == value)
                return false;
        }

        // 检查列
        for (auto i = 0; i < 9; i++)
        {
            if (i == row) continue;
            if (m_board[i][col]->value() == value)
                return false;
        }

        // 检查九宫格
        auto m = row / 3 * 3 + col / 3 + 1;     // 计算九宫格编号
        auto n = row % 3 * 3 + col % 3;     // 计算单元格在九宫格中的编号
        qDebug() << tr("第%1个九宫格的第%2个单元格").arg(m).arg(n);
        const auto& cells = m_ninecells.at(m);
        for (auto i = 0; i < 9; i++)
        {
            if (i == n) continue;
            if (cells[i]->value() == value)
                return false;
        }

        // 合法返回true
        return true;
    }

    void SudokuWidget::onSelectedCell(SudokuCell *cell)
    {
        if (m_selectedCell == cell)
            return;

        if (m_selectedCell != nullptr)
            m_selectedCell->unSelect();

        m_selectedCell = cell;
    }

    void SudokuWidget::onAppendCell(int num, SudokuCell *cell)
    {
        auto& cells = m_numcells[num - 1];
        for (auto it = cells.begin(); it != cells.end(); it++)
        {
            if (*it == cell)
                return;
        }
        cells.push_back(cell);
    }

    void SudokuWidget::onRemoveCell(int num, SudokuCell *cell)
    {
        auto& cells = m_numcells[num - 1];
        for (auto it = cells.begin(); it != cells.end(); it++)
        {
            if (*it == cell)
            {
                cells.erase(it);
                return;
            }
        }
    }

    void SudokuWidget::onCheckGame(int row, int col, int num)
    {
        auto result = isValid(row - 1, col - 1, num);
        if (result)
            qDebug() << tr("该值合法");
        else
            qDebug() << tr("该值非法");
    }

    void SudokuWidget::paintEvent(QPaintEvent *event)
    {
        // Q_UNUSED(event)
        auto s = std::min(width(), height()) - 20;
        auto w = s / 9;
        auto total_w = 9 * w + 6 + 8;

        // 计算坐标
        auto x0 = (this->width() - total_w) / 2;
        auto y0 = (this->height() - total_w) / 2;

        QPainter painter(this);
        painter.setRenderHint(QPainter::Antialiasing);

        // 第一步，画大九宫格
        auto p1 = QPen(m_lineColor, 2.f);
        auto p2 = QPen(m_lineColor, 0.8f);

        float x = x0;
        float y = y0;

        for (auto i = 0; i < 10; i++)
        {
            auto d = 0.5f;
            if (i % 3 == 0)
                painter.setPen(p1);
            else
                painter.setPen(p2);

            if (i % 3 == 0)
                d = 1.f;

            x += d;
            y += d;
            painter.drawLine(QPointF(x, y0 + 1), QPointF(x, y0 + total_w - 1));
            painter.drawLine(QPointF(x0 + 1, y), QPointF(x0 + total_w - 1, y));
            x += (w + d);
            y += (w + d);
        }

    }

    void SudokuWidget::resizeEvent(QResizeEvent *event)
    {
        Q_UNUSED(event)
        auto s = std::min(width(), height()) - 20;
        auto w = s / 9;      // 计算九宫格的
        auto total_w = 9 * w + 6 + 8;

        // 计算坐标
        auto x0 = (this->width() - total_w) / 2;
        auto y0 = (this->height() - total_w) / 2;

        auto y = y0;
        for (auto i = 1; i <= 9; i++)
        {
            if ((i - 1) % 3 == 0)
                y += 2;
            else
                y++;
            auto x = x0;
            for (auto j = 1; j <= 9; j++)
            {
                if ((j - 1) % 3 == 0)
                    x += 2;
                else
                    x++;
                m_board[i - 1][j - 1]->setGeometry(x, y, w , w);
                x += w;
            }
            y += w;
        }
    }

}

